﻿using System;
using System.Collections.Generic;
using System.Reflection;
using ClickLand.CorporacionPlaza.AccesoDato.Contratos;
using ClickLand.CorporacionPlaza.Comunes.Recursos;
using NHibernate;
using NHibernate.Criterion;
using Logger;

namespace ClickLand.CorporacionPlaza.AccesoDato.Implementacion.NHibernateMySql
{
    public abstract class DaoBase <T>: IDaoBase<T>
    {
        #region Atributos

        private ISession _session;

        #endregion

        /// <summary>
        /// Propiedad para obtener la sesion
        /// </summary>
        public ISession Session
        {
            get
            {
                if (null == _session)
                {
                    _session = NHibernateHelper.OpenSession();
                    log4net.Config.BasicConfigurator.Configure();
                }
                return _session;
            }
        }


        #region Implementation of IDaoBase<T>


        /// <summary> Metodo que obtiene todos los registro de una entidad dada </summary>
        /// <returns>lista de todos los registro de la entidad</returns>
        public IList<T> ObtenerTodos()
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Logger.Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            IList<T> listaEntidad;

            try
            {
                listaEntidad = Session.CreateCriteria(
                    typeof(T)).AddOrder(Order.Asc("Id")).List<T>();
            }
            catch (Exception e)
            {
                #region Instrumentacion Error
                if (Log.ErrorHabilitado)
                    Log.Error(e.Message + " " + e.InnerException);
                #endregion
                throw e;
            }
            finally
            {
                Session.Close();
            }
            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Logger.Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return listaEntidad;
        }


        /// <summary> Metodo que obtiene los datos de un registro en particular dado su id </summary>
        /// <param name="id">id unico de la entidad</param>
        /// <returns>datos del registro</returns>
        public T ObtenerPorId(long id)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Logger.Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            T entidad;

            try
            {
                entidad = Session.Load<T>(id);
                entidad.GetType();
            }
            catch (Exception e)
            {
                #region Instrumentacion Error
                if (Log.ErrorHabilitado)
                    Logger.Log.Info(e.Message + " " + e.InnerException);
                #endregion
                throw e;
            }
            finally
            {
                //Session.Close();
            }

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return entidad;
        }


        /// <summary> Metodo que inserta o modifica los datos de una entidad </summary>
        /// <param name="entidad">datos a insertar</param>
        /// <returns>true si se realizo la insercion false si no</returns>
        public bool InsertarOModificar(T entidad)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Logger.Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            bool exito;

            try
            {
                ITransaction tx = Session.BeginTransaction();
                Session.SaveOrUpdate(entidad);
                tx.Commit();
                exito = tx.WasCommitted;
            }
            catch (NullReferenceException e)
            {
                #region Instrumentacion Error
                if (Log.ErrorHabilitado)
                    Log.Info(e.Message + " " + e.InnerException);
                #endregion
                Session.Transaction.Rollback();

                throw e;
            }
            catch (Exception e)
            {
                #region Instrumentacion Error
                if (Log.ErrorHabilitado)
                    Logger.Log.Info( e.Message + " " + e.InnerException);
                #endregion
                Session.Transaction.Rollback();
                throw e;
            }
            finally
            {
                Session.Close();
            }

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Logger.Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return exito;
        }


        /// <summary> Metodo que elimina los datos de una entidad  </summary>
        /// <param name="entidad">datos a eliminar</param>
        /// <returns>true si se realizo la insercion false si no</returns>
        public bool Eliminar(T entidad)
        {
            #region Instrumentacion Entrada
            if (Log.InfoHabilitado)
                Logger.Log.Info(string.Format(Recurso.EntrandoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            bool exito;

            try
            {
                ITransaction tx = Session.BeginTransaction();
                Session.Delete(entidad);
                tx.Commit();
                exito = tx.WasCommitted;
            }
            catch (Exception e)
            {
                Session.Transaction.Rollback();
                Log.Error(e.Message);
                Log.Error(e.InnerException.Message);
                throw e;
            }
            finally
            {
                Session.Close();
            }

            #region Instrumentacion Salida
            if (Log.InfoHabilitado)
                Logger.Log.Info(string.Format(Recurso.SaliendoMetodo,MethodBase.GetCurrentMethod().Name));
            #endregion
            return exito;
        }

        #endregion
    }
}
